home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
Libraries
/
TurboTCP 1.0.1
/
TurboTCP.source
/
CTCPResolverCall.cp
< prev
next >
Wrap
Text File
|
1993-12-10
|
17KB
|
797 lines
/*
** CTCPResolverCall.cp
**
** TurboTCP support library
** TCP resolver call class
**
** Copyright © 1993, FrostByte Design / Eric Scouten
** Some portions adapted from file “dnr.c” Copyright © 1988 by Apple Computer. All rights reserved.
**
*/
#include "CTCPResolverCall.h"
#ifndef TurboTCPHeaders
#include <Folders.h>
#include <GestaltEqu.h>
#include <Traps.h>
#include <TCLUtilities.h>
#include <OSChecks.h>
#include "TurboTCP.const.h"
#endif
#include "CTCPDriver.h"
// procedure code numbers for DNR code segment
#define OPENRESOLVER 1L
#define CLOSERESOLVER 2L
#define STRTOADDR 3L
#define ADDRTOSTR 4L
#define ENUMCACHE 5L
#define ADDRTONAME 6L
#define HINFO 7L
#define MXINFO 8L
// declaration & initialization of class variables
Handle CTCPResolverCall::macDNRcode = NULL;
DNRProcPtr CTCPResolverCall::macDNRentry = NULL;
// —— initialize/destroy resolver ——
/*______________________________________________________________________
**
** ITCPResolverCall
**
** Initialize the resolver object. Must keep the object locked, since pointers are used
** frequently.
**
*/
void CTCPResolverCall::ITCPResolverCall (void)
{
// clear variables
inUse = FALSE;
disposeOnCompletion = FALSE;
pendingNotify = notifNone;
qEntry.qSelfLink = this;
qEntry.qType = resolverCall;
// initialize the collaborator object
CCollaborator::ICollaborator();
// prevent this from moving, since we use pointers
MoveHHi((Handle) this);
this->Lock(TRUE);
}
/*______________________________________________________________________
**
** Dispose
**
** Get rid of the resolver object. If a resolver operation is in progress, will dispose of
** itself when the current resolver operation is completed.
**
*/
void CTCPResolverCall::Dispose (void)
{
if (inUse)
disposeOnCompletion = TRUE;
else
CCollaborator::Dispose();
}
// —— initiate resolver calls ——
/*______________________________________________________________________
**
** DoStrToAddr
**
** Get the IP address of a host named by a DNS or dotted decimal string. Completion is
** handled by HandleStrToAddr.
**
** theHostName (char *): whos IP address do we need?
**
*/
void CTCPResolverCall::DoStrToAddr (char *theHostName)
{
OSErr theResult;
if (inUse)
FailOSErr(resolverInUse);
if (!gTCPDriver->CheckResolver())
FailOSErr(noResolverErr);
inUse = TRUE;
gTCPDriver->RegisterActiveResolver(this);
BlockMove(theHostName, &hostName, 255);
theResult = (*macDNRentry)(STRTOADDR, (char *) &hostName, &theHostInfo,
&PostponeStrToAddr, (char *) this);
// if call was completed immediately (with error or not), process it immediately
if (theResult != cacheFault) {
inUse = FALSE;
gTCPDriver->RemoveActiveResolver(this);
HandleStrToAddr();
}
}
/*______________________________________________________________________
**
** DoAddrToStr
**
** Convert an IP address to dotted decimal notation. This call can be used while the resolver
** object is otherwise in use, and is completed immediately.
**
** theIPaddr (ip_addr): the address to convert
** theString (char *): where to send the completed string (min. 16 chars)
**
*/
void CTCPResolverCall::DoAddrToStr (ip_addr theIPaddr, char *theString)
{
OSErr theResult;
if (!gTCPDriver->CheckResolver())
FailOSErr(noResolverErr);
(void) (*macDNRentry)(ADDRTOSTR, theIPaddr, theString);
}
/*______________________________________________________________________
**
** DoAddrToName
**
** Get the canonical name of a host as specified by IP address. Completion is handled by
** HandleAddrToName method.
**
** theIPaddr (ip_addr): the IP address to query
**
*/
void CTCPResolverCall::DoAddrToName (ip_addr theIPaddr)
{
OSErr theResult;
if (inUse)
FailOSErr(resolverInUse);
if (!gTCPDriver->CheckResolver())
FailOSErr(noResolverErr);
inUse = TRUE;
gTCPDriver->RegisterActiveResolver(this);
theResult = (*macDNRentry)(ADDRTONAME, theIPaddr, &theHostInfo,
&PostponeAddrToName, (char *) this);
// if call was completed immediately (with error or not), process it immediately
if (theResult != cacheFault) {
inUse = FALSE;
gTCPDriver->RemoveActiveResolver(this);
HandleAddrToName();
}
}
/*______________________________________________________________________
**
** DoHInfo
**
** Get the CPU type and operating system type of a remote host. Completion is handled by
** HandleHInfo.
**
** theHostName (char *): who we askin’ ‘bout anyway?
**
*/
void CTCPResolverCall::DoHInfo (char *theHostName)
{
OSErr theResult;
if (inUse)
FailOSErr(resolverInUse);
if (!gTCPDriver->CheckResolver())
FailOSErr(noResolverErr);
inUse = TRUE;
gTCPDriver->RegisterActiveResolver(this);
BlockMove(theHostName, &hostName, 255);
theResult = (*macDNRentry)(HINFO, (char *) &hostName, &theHMXInfo,
&PostponeHInfo, (char *) this);
// if call was completed immediately (with error or not), process it immediately
if (theResult != cacheFault) {
inUse = FALSE;
gTCPDriver->RemoveActiveResolver(this);
HandleHInfo();
}
}
/*______________________________________________________________________
**
** DoMXInfo
**
** Get the mailbox exchange (MX) info of a remote host. Completion is handled by
** HandleMXInfo.
**
** theHostName (char *): who we askin’ ‘bout anyway?
**
*/
void CTCPResolverCall::DoMXInfo (char *theHostName)
{
OSErr theResult;
if (inUse)
FailOSErr(resolverInUse);
if (!gTCPDriver->CheckResolver())
FailOSErr(noResolverErr);
inUse = TRUE;
gTCPDriver->RegisterActiveResolver(this);
BlockMove(theHostName, &hostName, 255);
theResult = (*macDNRentry)(MXINFO, (char *) &hostName, &theHMXInfo,
&PostponeMXInfo, (char *) this);
// if call was completed immediately (with error or not), process it immediately
if (theResult != cacheFault) {
inUse = FALSE;
gTCPDriver->RemoveActiveResolver(this);
HandleMXInfo();
}
}
// —— respond to completion of resolver calls ——
/*______________________________________________________________________
**
** ProcessNotify
**
** Handles any notifications passed to the resolver. This routine is free of interrupt-level
** constraints.
**
*/
void CTCPResolverCall::ProcessNotify (void)
{
// free this resolver object for future use
gTCPDriver->RemoveActiveResolver(this);
inUse = FALSE;
// dispatch notification to appropriate routine
switch (pendingNotify) {
case notifStrToAddr:
HandleStrToAddr();
break;
case notifAddrToName:
HandleAddrToName();
break;
case notifHInfo:
HandleHInfo();
break;
case notifMXInfo:
HandleMXInfo();
}
// if someone attempted to dispose this earlier, do it now
if (disposeOnCompletion)
Dispose();
}
/*______________________________________________________________________
**
** HandleStrToAddr (protected method)
**
** Respond to completion of a StrToAddr call.
**
*/
void CTCPResolverCall::HandleStrToAddr (void)
{
BroadcastChange(tcpResolverStrToAddr, &theHostInfo);
}
/*______________________________________________________________________
**
** HandleAddrToName (protected method)
**
** Respond to completion of an AddrToName call.
**
*/
void CTCPResolverCall::HandleAddrToName (void)
{
BroadcastChange(tcpResolverAddrToName, &theHostInfo);
}
/*______________________________________________________________________
**
** HandleHInfo (protected method)
**
** Respond to completion of an HInfo call.
**
*/
void CTCPResolverCall::HandleHInfo (void)
{
BroadcastChange(tcpResolverHInfo, &theHMXInfo);
}
/*______________________________________________________________________
**
** HandleMXInfo (protected method)
**
** Respond to completion of an MXInfo call.
**
*/
void CTCPResolverCall::HandleMXInfo (void)
{
BroadcastChange(tcpResolverMXInfo, &theHMXInfo);
}
// —— open/close TCP resolver ——
/*______________________________________________________________________
**
** OpenResolver (static method)
**
** Find the MacTCP DNR code resource and read it. Save the location of the resolver resource
** for later use.
**
*/
void CTCPResolverCall::OpenResolver (void)
{
short vRefNum;
short refnum;
long dirID;
short fRef;
OSErr rc;
// is the resolver already there?
if (macDNRentry)
return;
// open the MacTCP driver to get DNR resources
TRY {
refnum = OpenTheDNR();
}
CATCH {
NO_PROPAGATE; // ignore failures since the resource may
// have been installed in the System file
// (if running on a Mac 512Ke)
}
ENDTRY;
// load the DNR resource package
macDNRcode = GetIndResource('dnrp', 1);
FailNIL(macDNRcode);
DetachResource(macDNRcode);
if (refnum != -1)
CloseResFile(refnum);
// lock the DNR resource since it cannot be relocated while opened
MoveHHi(macDNRcode);
HLock(macDNRcode);
macDNRentry = (DNRProcPtr) *macDNRcode;
// check for “hosts” file in System Folder (BRB)
GetSystemFolder(&vRefNum, &dirID);
rc = HOpen(vRefNum, dirID, "\pHosts", fsRdPerm, &fRef);
switch (rc) {
case noErr:
FSClose(fRef);
break;
case fnfErr:
if ((rc = HCreate(vRefNum, dirID, "\pHosts", 'ttxt', 'TEXT')) != noErr)
ErrorAlert(rc, SpecifyMsg(1001, 1));
break;
default:
break;
}
// ask the DNR resource to open the resolver
rc = (*macDNRentry)(OPENRESOLVER, NULL); // send it a null hosts file name
if (rc != noErr) {
HUnlock(macDNRcode); // problem with open resolver, flush DNR resource
DisposHandle(macDNRcode);
macDNRcode = NULL;
macDNRentry = NULL;
FailOSErr(rc); // signal failure of DNR
}
}
/*______________________________________________________________________
**
** CloseResolver (static method)
**
** Shut down the DNR code resource. Does nothing if the resolver was never loaded.
**
*/
void CTCPResolverCall::CloseResolver (void)
{
// ensure that we had a resolver to begin with
if (macDNRentry == NULL)
return;
// call CloseResolver function in DNR
(void) (*macDNRentry)(CLOSERESOLVER);
// release the DNR code resource
HUnlock(macDNRcode);
DisposHandle(macDNRcode);
macDNRcode = NULL;
macDNRentry = NULL;
}
/*______________________________________________________________________
**
** OpenTheDNR (protected static method)
**
** Search in several places for the MacTCP DNR code resource. Tries the Control Panels
** folder and the System folder.
**
** return (short): reference number to resource file
**
*/
short CTCPResolverCall::OpenTheDNR (void)
{
short refnum;
short vRefNum;
long dirID;
// first search Control Panels for MacTCP 1.1.x
GetCPanelFolder(&vRefNum, &dirID);
refnum = SearchFolderForDNRP('cdev', 'ztcp', vRefNum, dirID);
if (refnum != -1)
return (refnum);
// next search System Folder for MacTCP 1.0.x
GetSystemFolder(&vRefNum, &dirID);
refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
if (refnum != -1)
return (refnum);
// finally, search Control Panels for MacTCP 1.0.x
GetCPanelFolder(&vRefNum, &dirID);
refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
if (refnum != -1)
return (refnum);
return (-1);
}
/*______________________________________________________________________
**
** SearchFolderForDNRP (protected static method)
**
** Search a folder for files that might contain the 'dnrp' resource.
**
** targetType (OSType): file type that we are looking for
** targetCreator (OSType): file creator "" ""
** vRefNum (short): volume ref num
** dirID (long): directory number on the volume
**
** return (short): the refnum of the file if found, -1 if not found
**
*/
short CTCPResolverCall::SearchFolderForDNRP (long targetType, long targetCreator,
short vRefNum, long dirID)
{
HParamBlockRec fi;
Str255 filename;
short refnum;
// initialize our search mechanism
fi.fileParam.ioCompletion = nil;
fi.fileParam.ioNamePtr = filename;
fi.fileParam.ioVRefNum = vRefNum;
fi.fileParam.ioDirID = dirID;
fi.fileParam.ioFDirIndex = 1;
// keep looking till we run out of files
while (PBHGetFInfo(&fi, false) == noErr) {
// scan the folder for files that match our type & creator
if (fi.fileParam.ioFlFndrInfo.fdType == targetType &&
fi.fileParam.ioFlFndrInfo.fdCreator == targetCreator) {
// type/creator match, look for the resource
refnum = HOpenResFile(vRefNum, dirID, filename, fsRdPerm);
if (GetIndResource('dnrp', 1) == NULL)
CloseResFile(refnum);
else
return (refnum);
}
// no match or no resource, try next file in folder
fi.fileParam.ioFDirIndex++;
fi.fileParam.ioDirID = dirID; // PBHGetFInfo() clobbers ioDirID
}
return (-1); // nothing found
}
/*______________________________________________________________________
**
** GetSystemFolder (protected static method)
**
** Return the ID of the current system folder.
**
** vRefNumP (short *): returns volume ref number
** dirIDP (long *): returns directory ID
**
*/
void CTCPResolverCall::GetSystemFolder (short *vRefNumP, long *dirIDP)
{
SysEnvRec info;
long wdProcID;
SysEnvirons(1, &info);
if (GetWDInfo(info.sysVRefNum, vRefNumP, dirIDP, &wdProcID) != noErr) {
*vRefNumP = 0;
*dirIDP = 0;
}
}
/*______________________________________________________________________
**
** GetCPanelFolder (protected static method)
**
** Return the ID of the current “Control Panels” folder.
**
** vRefNumP (short *): returns volume ref number
** dirIDP (long *): returns directory ID
**
*/
void CTCPResolverCall::GetCPanelFolder (short *vRefNumP, long *dirIDP)
{
Boolean hasFolderMgr = false;
long feature;
// see if we have the Folder Manager available
if (TrapAvailable((short) _Gestalt))
if (Gestalt(gestaltFindFolderAttr, &feature) == noErr)
hasFolderMgr = TRUE;
// if folder manager, use it; else return system folder
if (!hasFolderMgr) {
GetSystemFolder(vRefNumP, dirIDP);
return;
}
else {
if (FindFolder(kOnSystemDisk, kControlPanelFolderType,
kDontCreateFolder, vRefNumP, dirIDP) != noErr) {
*vRefNumP = 0;
*dirIDP = 0;
}
}
}
/***********************************************************************
************************************************************************
**
** INTERRUPT-LEVEL routines follow. These routines cannot make memory allocations, cannot make
** synchronous TCP calls, and cannot use the Think C profiler.
**
*/
#pragma options(!profile)
// —— interrupt-level methods: delay processing for non-interrupt status ——
/*______________________________________________________________________
**
** PostponeNotify
**
** Respond to notification that a DNR call was completed. Delays processing of notification
** until the next net-event call. This method merely logs the kind of notification and adds this
** resolver to the list of resolvers to be processed next time through the event loop.
**
** theNotifType (NotifType): which resolver call was completed
**
*/
void CTCPResolverCall::PostponeNotify (NotifType theNotifType)
{
pendingNotify = theNotifType;
Enqueue((QElemPtr) &qEntry, &(gTCPDriver->asyncQueue));
}
/*______________________________________________________________________
**
** PostponeStrToAddr (protected static method)
**
** Respond to notification that the StrToAddr call was completed.
**
** hostInfoPtr (…): pointer to the DNR data structure (ignored)
** userDataPtr (char *): user data pointer (assumed to be CTCPResolver *)
**
*/
pascal void CTCPResolverCall::PostponeStrToAddr (struct hostInfo *hostInfoPtr, char *userDataPtr)
{
if (userDataPtr)
((CTCPResolverCall *) userDataPtr)->PostponeNotify(notifStrToAddr);
}
/*______________________________________________________________________
**
** PostponeAddrToName (protected static method)
**
** Respond to notification that the AddrToName call was completed.
**
** hostInfoPtr (…): pointer to the DNR data structure (ignored)
** userDataPtr (char *): user data pointer (assumed to be CTCPResolver *)
**
*/
pascal void CTCPResolverCall::PostponeAddrToName (struct hostInfo *hostInfoPtr, char *userDataPtr)
{
if (userDataPtr)
((CTCPResolverCall *) userDataPtr)->PostponeNotify(notifAddrToName);
}
/*______________________________________________________________________
**
** PostponeHInfo (protected static method)
**
** Respond to notification that the HInfo call was completed.
**
** hostInfoPtr (…): pointer to the DNR data structure (ignored)
** userDataPtr (char *): user data pointer (assumed to be CTCPResolver *)
**
*/
pascal void CTCPResolverCall::PostponeHInfo (struct returnRec *returnRecPtr, char *userDataPtr)
{
if (userDataPtr)
((CTCPResolverCall *) userDataPtr)->PostponeNotify(notifHInfo);
}
/*______________________________________________________________________
**
** PostponeMXInfo (protected static method)
**
** Respond to notification that the MXInfo call was completed.
**
** hostInfoPtr (…): pointer to the DNR data structure (ignored)
** userDataPtr (char *): user data pointer (assumed to be CTCPResolver *)
**
*/
pascal void CTCPResolverCall::PostponeMXInfo (struct returnRec *returnRecPtr, char *userDataPtr)
{
if (userDataPtr)
((CTCPResolverCall *) userDataPtr)->PostponeNotify(notifMXInfo);
}